# -*- coding: UTF-8 -*-
from django.core.cache import cache
from django.utils.httpwrappers import HttpResponseNotModified
from django.utils.text import compress_string
import datetime, md5

def cache_page(view_func, cache_timeout, key_prefix=''):
    """
    Un décorateur destiné aux vues souhaitant obtenir la page demandée à partir
    du cache (et remplir le cache si la page n'y est pas encore). Ce décorateur
    se charge aussi des balises ETag, et compresse la page grâce à gzip si le
    client le permet.

    La clé utilisée pour le stockage au sein du cache est générée à partir de 
    l'URL de la page plus le préfixe facultatif key_prefix. Utilisez key_prefix 
    si votre installation de Django gère plusieurs sites utilisant un cache; 
    autrement, le cache d'un site donné pourrait influer sur le cache d'un 
    autre. Un bon exemple de préfixe serait d'utiliser 
    sites.get_current().domain, car c'est une chaîne unique parmi toutes les 
    instances de Django présentes sur un serveur donné.
    """
    def _check_cache(request, *args, **kwargs):
        try:
            accept_encoding = request.META['HTTP_ACCEPT_ENCODING']
        except KeyError:
            accept_encoding = ''
        accepts_gzip = 'gzip' in accept_encoding
        cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % (key_prefix, request.path, accepts_gzip)
        response = cache.get(cache_key, None)
        if response is None:
            response = view_func(request, *args, **kwargs)
            content = response.get_content_as_string('utf-8')
            if accepts_gzip:
                content = compress_string(content)
                response.content = content
                response['Content-Encoding'] = 'gzip'
            response['ETag'] = md5.new(content).hexdigest()
            response['Content-Length'] = '%d' % len(content)
            response['Last-Modified'] = datetime.datetime.utcnow().strftime('%a %d %b %Y %H:%M:%S GMT')
            cache.set(cache_key, response, cache_timeout)
        else:
            # La logique du code qui suit provient de 
            # http://simon.incutio.com/archive/2003/04/23/conditionalGet
            try:
                if_none_match = request.META['HTTP_IF_NONE_MATCH']
            except KeyError:
                if_none_match = None
            try:
                if_modified_since = request.META['HTTP_IF_MODIFIED_SINCE']
            except KeyError:
                if_modified_since = None
            if if_none_match is None and if_modified_since is None:
                pass
            elif if_none_match is not None and response['ETag'] != if_none_match:
                pass
            elif if_modified_since is not None and response['Last-Modified'] != if_modified_since:
                pass
            else:
                return HttpResponseNotModified()
        return response
    return _check_cache